using AbpMvc.Demo.Routes;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ShardingCore;
using System;
using System.Collections.Generic;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.SqlServer;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.Studio;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.Uow;

namespace AbpMvc.Demo.EntityFrameworkCore;

[DependsOn(
    typeof(DemoDomainModule),
    typeof(AbpPermissionManagementEntityFrameworkCoreModule),
    typeof(AbpSettingManagementEntityFrameworkCoreModule),
    typeof(AbpEntityFrameworkCoreSqlServerModule),
    typeof(AbpBackgroundJobsEntityFrameworkCoreModule),
    typeof(AbpAuditLoggingEntityFrameworkCoreModule),
    typeof(AbpFeatureManagementEntityFrameworkCoreModule),
    typeof(AbpIdentityEntityFrameworkCoreModule),
    typeof(AbpOpenIddictEntityFrameworkCoreModule),
    typeof(AbpTenantManagementEntityFrameworkCoreModule),
    typeof(BlobStoringDatabaseEntityFrameworkCoreModule)
    )]
public class DemoEntityFrameworkCoreModule : AbpModule
{
    public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
    {
        builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information);
    });
    public override void PreConfigureServices(ServiceConfigurationContext context)
    {

        DemoEfCoreEntityExtensionMappings.Configure();
    }

    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddAbpDbContext<DemoDbContext>(options =>
        {
                /* Remove "includeAllEntities: true" to create
                 * default repositories only for aggregate roots */
            options.AddDefaultRepositories(includeAllEntities: true);
        });

        if (AbpStudioAnalyzeHelper.IsInAnalyzeMode)
        {
            return;
        }

        Configure<AbpDbContextOptions>(options =>
        {
            /* The main point to change your DBMS.
             * See also DemoDbContextFactory for EF Core tooling. */

            options.UseSqlServer();
            options.Configure<DemoDbContext>(innerContext =>
            {
                //innerContext.DbContextOptions
                //    .ReplaceService<IChangeTrackerFactory, ShardingChangeTrackerFactory>();
                innerContext.DbContextOptions.UseDefaultSharding<DemoDbContext>(innerContext.ServiceProvider);
            });

        });

        context.Services.AddShardingConfigure<DemoDbContext>()
                .UseRouteConfig(op =>
                {
                    op.AddShardingDataSourceRoute<TodoDataSourceRoute>();
                    op.AddShardingTableRoute<TodoTableRoute>();
                })
                .UseConfig((sp, op) =>
                {

                    //var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
                    op.UseShardingQuery((conStr, builder) =>
                    {
                        builder.UseSqlServer(conStr).UseLoggerFactory(efLogger);
                    });
                    op.UseShardingTransaction((connection, builder) =>
                    {
                        builder.UseSqlServer(connection).UseLoggerFactory(efLogger);
                    });
                    op.UseShardingMigrationConfigure(builder =>
                    {
                        builder.ReplaceService<IMigrationsSqlGenerator, ShardingSqlServerMigrationsSqlGenerator>();
                    });
                    op.AddDefaultDataSource("ds0", "Server=(LocalDb)\\MSSQLLocalDB;Database=Demo;Trusted_Connection=True;TrustServerCertificate=true");
                    op.AddExtraDataSource(sp =>
                    {
                        return new Dictionary<string, string>()
                        {
                            { "ds1", "Server=(LocalDb)\\MSSQLLocalDB;Database=Demo1;Trusted_Connection=True;TrustServerCertificate=true" },
                            { "ds2", "Server=(LocalDb)\\MSSQLLocalDB;Database=Demo2;Trusted_Connection=True;TrustServerCertificate=true" }
                        };
                    });
                })
                .AddShardingCore();

    }
}
